The de-duplication of Units just doesn't work without it.
// Throw in the profile we're compiling with. This helps caching
// panic=abort and panic=unwind artifacts, additionally with various
// settings like debuginfo and whatnot.
- cx.unit_profile(unit).hash(&mut hasher);
+ unit.profile.hash(&mut hasher);
unit.mode.hash(&mut hasher);
// Artifacts compiled for the host should have a different metadata
use core::{Package, PackageId, PackageSet, Resolve, Target};
use core::{Dependency, Workspace};
-use core::profiles::{Profile, ProfileFor, Profiles};
+use core::profiles::{Profile, Profiles};
use ops::CompileMode;
use util::{internal, profile, Cfg, CfgExpr, Config};
use util::errors::{CargoResult, CargoResultExt};
/// to be confused with *target-triple* (or *target architecture* ...), the target arch for a
/// build.
pub target: &'a Target,
- /// This indicates the purpose of the target for profile selection. See
- /// `ProfileFor` for more details.
- pub profile_for: ProfileFor,
+ /// The profile contains information about *how* the build should be run, including debug
+ /// level, etc.
+ pub profile: Profile,
/// Whether this compilation unit is for the host or target architecture.
///
/// For example, when
incremental_env: Option<bool>,
unit_dependencies: HashMap<Unit<'a>, Vec<Unit<'a>>>,
- unit_profiles: HashMap<Unit<'a>, Profile>,
files: Option<CompilationFiles<'a, 'cfg>>,
}
build_script_overridden: HashSet::new(),
unit_dependencies: HashMap::new(),
- unit_profiles: HashMap::new(),
files: None,
extra_compiler_args,
};
let deps = build_unit_dependencies(units, self)?;
self.unit_dependencies = deps;
- self.unit_profiles = self.profiles.build_unit_profiles(units, self);
- let files = CompilationFiles::new(
- units,
- host_layout,
- target_layout,
- export_dir,
- self.ws,
- self,
- );
+ let files =
+ CompilationFiles::new(units, host_layout, target_layout, export_dir, self.ws, self);
self.files = Some(files);
Ok(())
}
self.build_config.jobs
}
- pub fn incremental_args(
- &self,
- unit: &Unit,
- profile_incremental: bool,
- ) -> CargoResult<Vec<String>> {
+ pub fn incremental_args(&self, unit: &Unit) -> CargoResult<Vec<String>> {
// There's a number of ways to configure incremental compilation right
// now. In order of descending priority (first is highest priority) we
// have:
// have it enabled by default while release profiles have it disabled
// by default.
let global_cfg = self.config.get_bool("build.incremental")?.map(|c| c.val);
- let incremental = match (self.incremental_env, global_cfg, profile_incremental) {
+ let incremental = match (self.incremental_env, global_cfg, unit.profile.incremental) {
(Some(v), _, _) => v,
(None, Some(false), _) => false,
(None, _, other) => other,
Kind::Target => &self.target_info,
}
}
-
- /// Returns the profile for a given unit.
- /// This should not be called until profiles are computed in
- /// `prepare_units`.
- pub fn unit_profile(&self, unit: &Unit<'a>) -> &Profile {
- &self.unit_profiles[unit]
- }
}
/// Acquire extra flags to pass to the compiler from various locations.
use super::{Context, Kind, Unit};
use core::dependency::Kind as DepKind;
use core::profiles::ProfileFor;
-use core::Target;
+use core::{Package, Target};
use ops::CompileMode;
use std::collections::HashMap;
use CargoResult;
) -> CargoResult<HashMap<Unit<'a>, Vec<Unit<'a>>>> {
let mut deps = HashMap::new();
for unit in roots.iter() {
- deps_of(unit, cx, &mut deps, unit.profile_for)?;
+ // Dependencies of tests should not have `panic` set.
+ let profile_for = if unit.mode.is_any_test() {
+ ProfileFor::TestDependency
+ } else {
+ ProfileFor::Any
+ };
+ deps_of(unit, cx, &mut deps, profile_for)?;
}
Ok(deps)
}).filter_map(|(id, _)| match cx.get_package(id) {
Ok(pkg) => pkg.targets().iter().find(|t| t.is_lib()).map(|t| {
let mode = check_or_build_mode(&unit.mode, t);
- Ok((
- Unit {
- pkg,
- target: t,
- profile_for,
- kind: unit.kind.for_target(t),
- mode,
- },
- profile_for,
- ))
+ let unit = new_unit(cx, pkg, t, profile_for, unit.kind.for_target(t), mode);
+ Ok((unit, profile_for))
}),
Err(e) => Some(Err(e)),
})
if unit.target.is_lib() && unit.mode != CompileMode::Doctest {
return Ok(ret);
}
- ret.extend(maybe_lib(unit, profile_for));
+ ret.extend(maybe_lib(cx, unit, profile_for));
Ok(ret)
}
target: not_custom_build,
// The profile here isn't critical. We are just using this temp unit
// for fetching dependencies that might have `links`.
- profile_for: ProfileFor::Any,
+ profile: unit.profile,
kind: unit.kind,
mode: CompileMode::Build,
};
dep_build_script(unit)
})
.chain(Some((
- Unit {
- pkg: unit.pkg,
- target: unit.target,
- profile_for: ProfileFor::CustomBuild,
- kind: Kind::Host, // build scripts always compiled for the host
- mode: CompileMode::Build,
- },
+ new_unit(
+ cx,
+ unit.pkg,
+ unit.target,
+ ProfileFor::CustomBuild,
+ Kind::Host, // build scripts always compiled for the host
+ CompileMode::Build,
+ ),
+ // All dependencies of this unit should use profiles for custom
+ // builds.
ProfileFor::CustomBuild,
)))
.collect())
// rustdoc only needs rmeta files for regular dependencies.
// However, for plugins/proc-macros, deps should be built like normal.
let mode = check_or_build_mode(&unit.mode, lib);
- ret.push((
- Unit {
- pkg: dep,
- target: lib,
- profile_for: ProfileFor::Any,
- kind: unit.kind.for_target(lib),
- mode,
- },
+ let unit = new_unit(
+ cx,
+ dep,
+ lib,
ProfileFor::Any,
- ));
+ unit.kind.for_target(lib),
+ mode,
+ );
+ ret.push((unit, ProfileFor::Any));
if let CompileMode::Doc { deps: true } = unit.mode {
- ret.push((
- Unit {
- pkg: dep,
- target: lib,
- profile_for: ProfileFor::Any,
- kind: unit.kind.for_target(lib),
- mode: unit.mode,
- },
+ let unit = new_unit(
+ cx,
+ dep,
+ lib,
ProfileFor::Any,
- ));
+ unit.kind.for_target(lib),
+ unit.mode,
+ );
+ ret.push((unit, ProfileFor::Any));
}
}
// If we document a binary, we need the library available
if unit.target.is_bin() {
- ret.extend(maybe_lib(unit, ProfileFor::Any));
+ ret.extend(maybe_lib(cx, unit, ProfileFor::Any));
}
Ok(ret)
}
-fn maybe_lib<'a>(unit: &Unit<'a>, profile_for: ProfileFor) -> Option<(Unit<'a>, ProfileFor)> {
+fn maybe_lib<'a>(
+ cx: &Context,
+ unit: &Unit<'a>,
+ profile_for: ProfileFor,
+) -> Option<(Unit<'a>, ProfileFor)> {
let mode = check_or_build_mode(&unit.mode, unit.target);
unit.pkg.targets().iter().find(|t| t.linkable()).map(|t| {
- (
- Unit {
- pkg: unit.pkg,
- target: t,
- profile_for,
- kind: unit.kind.for_target(t),
- mode,
- },
- profile_for,
- )
+ let unit = new_unit(cx, unit.pkg, t, profile_for, unit.kind.for_target(t), mode);
+ (unit, profile_for)
})
}
.iter()
.find(|t| t.is_custom_build())
.map(|t| {
+ // The profile stored in the Unit is the profile for the thing
+ // the custom build script is running for.
+ // TODO: Fix this for different profiles that don't affect the
+ // build.rs environment variables.
(
Unit {
pkg: unit.pkg,
target: t,
- // The profile for *running* the build script will actually be the
- // target the build script is running for (so that the environment
- // variables get set correctly). This is overridden in
- // `Profiles::build_unit_profiles`, so the exact value here isn't
- // critical.
- profile_for: ProfileFor::CustomBuild,
+ profile: unit.profile,
kind: unit.kind,
mode: CompileMode::RunCustomBuild,
},
_ => CompileMode::Build,
}
}
+
+fn new_unit<'a>(
+ cx: &Context,
+ pkg: &'a Package,
+ target: &'a Target,
+ profile_for: ProfileFor,
+ kind: Kind,
+ mode: CompileMode,
+) -> Unit<'a> {
+ let profile = cx.profiles.get_profile(
+ &pkg.name(),
+ cx.ws.is_member(pkg),
+ profile_for,
+ mode,
+ cx.build_config.release,
+ );
+ Unit {
+ pkg,
+ target,
+ profile,
+ kind,
+ mode,
+ }
+}
// package's library profile.
let to_exec = to_exec.into_os_string();
let mut cmd = cx.compilation.host_process(to_exec, unit.pkg)?;
- let profile = cx.unit_profile(unit).clone();
cmd.env("OUT_DIR", &build_output)
.env("CARGO_MANIFEST_DIR", unit.pkg.root())
.env("NUM_JOBS", &cx.jobs().to_string())
Kind::Target => cx.build_config.target_triple(),
},
)
- .env("DEBUG", &profile.debuginfo.is_some().to_string())
- .env("OPT_LEVEL", &profile.opt_level.to_string())
+ .env("DEBUG", &unit.profile.debuginfo.is_some().to_string())
+ .env("OPT_LEVEL", &unit.profile.opt_level.to_string())
.env(
"PROFILE",
if cx.build_config.release {
} else {
cx.rustflags_args(unit)?
};
- let profile_hash = {
- let profile = cx.unit_profile(unit);
- util::hash_u64(&(
- profile,
- unit.mode,
- cx.incremental_args(unit, profile.incremental)?,
- ))
- };
let fingerprint = Arc::new(Fingerprint {
rustc: util::hash_u64(&cx.build_config.rustc.verbose_version),
target: util::hash_u64(&unit.target),
- profile: profile_hash,
+ profile: util::hash_u64(&(&unit.profile, unit.mode, cx.incremental_args(unit)?)),
// Note that .0 is hashed here, not .1 which is the cwd. That doesn't
// actually affect the output artifact so there's no need to hash it.
path: util::hash_u64(&super::path_args(cx, unit).0),
use jobserver::{Acquired, HelperThread};
use core::{PackageId, Target};
-use core::profiles::ProfileFor;
+use core::profiles::Profile;
use ops::CompileMode;
use util::{Config, DependencyQueue, Dirty, Fresh, Freshness};
use util::{internal, profile, CargoResult, CargoResultExt, ProcessBuilder};
struct Key<'a> {
pkg: &'a PackageId,
target: &'a Target,
- profile_for: ProfileFor,
+ profile: Profile,
kind: Kind,
mode: CompileMode,
}
Key {
pkg: unit.pkg.package_id(),
target: unit.target,
- profile_for: unit.profile_for,
+ profile: unit.profile,
kind: unit.kind,
mode: unit.mode,
}
let unit = Unit {
pkg: cx.get_package(self.pkg)?,
target: self.target,
- profile_for: self.profile_for,
+ profile: self.profile,
kind: self.kind,
mode: self.mode,
};
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
- "{} => {}/{:?} => {:?}",
- self.pkg, self.target, self.mode, self.kind
+ "{} => {}/{} => {:?}",
+ self.pkg, self.target, self.profile, self.kind
)
}
}
let export_dir = cx.files().export_dir(unit);
let package_id = unit.pkg.package_id().clone();
let target = unit.target.clone();
- let profile = cx.unit_profile(unit).clone();
+ let profile = unit.profile;
let unit_mode = unit.mode;
let features = cx.resolve
.features_sorted(&package_id)
overflow_checks,
rpath,
ref panic,
- incremental,
..
- } = *cx.unit_profile(unit);
+ } = unit.profile;
let test = unit.mode.is_any_test();
cmd.arg("--crate-name").arg(&unit.target.crate_name());
"linker=",
cx.linker(unit.kind).map(|s| s.as_ref()),
);
- cmd.args(&cx.incremental_args(unit, incremental)?);
+ cmd.args(&cx.incremental_args(unit)?);
Ok(())
}
-use std::collections::HashMap;
use std::{cmp, fmt, hash};
use ops::CompileMode;
use util::toml::{StringOrBool, TomlProfile, U32OrBool};
-use core::compiler::Context;
-use core::compiler::Unit;
use core::interning::InternedString;
/// Collection of all user profiles.
/// Retrieve the profile for a target.
/// `is_member` is whether or not this package is a member of the
/// workspace.
- fn get_profile(
+ pub fn get_profile(
&self,
pkg_name: &str,
is_member: bool,
self.dev.profile_for("", true, ProfileFor::Any)
}
}
-
- /// Build a mapping from Unit -> Profile for all the given units and all
- /// of their dependencies.
- pub fn build_unit_profiles<'a, 'cfg>(
- &self,
- units: &[Unit<'a>],
- cx: &Context<'a, 'cfg>,
- ) -> HashMap<Unit<'a>, Profile> {
- let mut result = HashMap::new();
- for unit in units.iter() {
- self.build_unit_profiles_rec(unit, None, cx, &mut result);
- }
- result
- }
-
- fn build_unit_profiles_rec<'a, 'cfg>(
- &self,
- unit: &Unit<'a>,
- parent: Option<&Unit<'a>>,
- cx: &Context<'a, 'cfg>,
- map: &mut HashMap<Unit<'a>, Profile>,
- ) {
- if !map.contains_key(unit) {
- let for_unit = if unit.mode.is_run_custom_build() {
- // The profile for *running* a custom build script is the
- // target the script is running for. This allows
- // `custom_build::build_work` to set the correct environment
- // settings.
- //
- // In the case of `cargo clean -p`, it creates artificial
- // units to compute filenames, without a dependency hierarchy,
- // so we don't have a parent here. That should be OK, it
- // only affects the environment variables used to *run*
- // `build.rs`.
- parent.unwrap_or(unit)
- } else {
- unit
- };
- let profile = self.get_profile(
- &for_unit.pkg.name(),
- cx.ws.is_member(for_unit.pkg),
- for_unit.profile_for,
- for_unit.mode,
- cx.build_config.release,
- );
- map.insert(*unit, profile);
- let deps = cx.dep_targets(unit);
- for dep in &deps {
- self.build_unit_profiles_rec(dep, Some(unit), cx, map);
- }
- }
- }
}
/// An object used for handling the profile override hierarchy.
impl ProfileMaker {
fn profile_for(&self, pkg_name: &str, is_member: bool, profile_for: ProfileFor) -> Profile {
- let mut profile = self.default.clone();
+ let mut profile = self.default;
if let Some(ref toml) = self.toml {
merge_profile(&mut profile, toml);
if profile_for == ProfileFor::CustomBuild {
}
match toml.lto {
Some(StringOrBool::Bool(b)) => profile.lto = Lto::Bool(b),
- Some(StringOrBool::String(ref n)) => profile.lto = Lto::Named(n.clone()),
+ Some(StringOrBool::String(ref n)) => profile.lto = Lto::Named(InternedString::new(n)),
None => {}
}
if toml.codegen_units.is_some() {
/// Profile settings used to determine which compiler flags to use for a
/// target.
-#[derive(Debug, Clone, Eq)]
+#[derive(Debug, Clone, Copy, Eq)]
pub struct Profile {
pub name: &'static str,
pub opt_level: InternedString,
}
/// The link-time-optimization setting.
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum Lto {
/// False = no LTO
/// True = "Fat" LTO
Bool(bool),
/// Named LTO settings like "thin".
- Named(String),
+ Named(InternedString),
}
/// A flag used in `Unit` to indicate the purpose for the target.
for kind in [Kind::Host, Kind::Target].iter() {
for mode in CompileMode::all_modes() {
for profile_for in ProfileFor::all_values() {
+ let profile = profiles.get_profile(
+ &pkg.name(),
+ ws.is_member(pkg),
+ profile_for,
+ mode,
+ opts.release,
+ );
units.push(Unit {
pkg,
target,
- profile_for,
+ profile,
kind: *kind,
mode,
});
use core::compiler::{BuildConfig, Compilation, Context, DefaultExecutor, Executor};
use core::compiler::{Kind, Unit};
-use core::profiles::ProfileFor;
+use core::profiles::{ProfileFor, Profiles};
use core::resolver::{Method, Resolve};
use core::{Package, Source, Target};
use core::{PackageId, PackageIdSpec, TargetKind, Workspace};
let mut extra_compiler_args = HashMap::new();
let units = generate_targets(
+ ws,
+ profiles,
&to_builds,
filter,
default_arch_kind,
mode,
&resolve_with_overrides,
+ release,
)?;
if let Some(args) = extra_args {
/// compile. Dependencies for these targets are computed later in
/// `unit_dependencies`.
fn generate_targets<'a>(
+ ws: &Workspace,
+ profiles: &Profiles,
packages: &[&'a Package],
filter: &CompileFilter,
default_arch_kind: Kind,
mode: CompileMode,
resolve: &Resolve,
+ release: bool,
) -> CargoResult<Vec<Unit<'a>>> {
let mut units = Vec::new();
// Helper for creating a Unit struct.
let new_unit =
|pkg: &'a Package, target: &'a Target, mode: CompileMode, profile_for: ProfileFor| {
- let actual_profile_for = if profile_for != ProfileFor::Any {
- profile_for
- } else if mode.is_any_test() {
- // Force dependencies of this unit to not set `panic`.
- ProfileFor::TestDependency
- } else {
- profile_for
- };
- let actual_mode = match mode {
+ let mode = match mode {
CompileMode::Test => {
if target.is_example() {
// Examples are included as regular binaries to verify
// that they compile.
+ // TODO: Broken - Dependencies of examples can be
+ // built with `panic`, which will cause `rustdoc` to
+ // fail with linking multiple binaries.
CompileMode::Build
} else {
CompileMode::Test
} else {
default_arch_kind
};
+ let profile =
+ profiles.get_profile(&pkg.name(), ws.is_member(pkg), profile_for, mode, release);
Unit {
pkg,
target,
- profile_for: actual_profile_for,
+ profile,
kind,
- mode: actual_mode,
+ mode,
}
};
proposals.extend(default_units);
if mode == CompileMode::Test {
// Include the lib as it will be required for doctests.
+ // TODO: Broken - Dependencies won't have ProfileFor::TestDependency.
if let Some(t) = pkg.targets().iter().find(|t| t.is_lib() && t.doctested()) {
- proposals.push((
- new_unit(pkg, t, CompileMode::Build, ProfileFor::TestDependency),
- false,
- ));
+ proposals
+ .push((new_unit(pkg, t, CompileMode::Build, ProfileFor::Any), false));
}
}
}